package cn.studyjava.verify.service.impl;

import java.util.Date;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import cn.studyjava.verify.common.Const;
import cn.studyjava.verify.common.enums.VerifyEnum;
import cn.studyjava.verify.model.ImageVerify;
import cn.studyjava.verify.model.vo.AuthVO;
import cn.studyjava.verify.mybatis.entity.Auth;
import cn.studyjava.verify.service.IAuthService;
import cn.studyjava.verify.service.IGenerateCodeService;
import cn.studyjava.verify.service.IVerifyService;
import cn.studyjava.verify.util.GeneratorKey;
import cn.studyjava.verify.util.JsonUtil;
import cn.studyjava.verify.util.ThreadPoolExecutorUtil;

/**
 * <p>
 * Description:
 * </p>
 * 
 * @author: zsljava
 * @version 1.0.0
 * <p>
 * History:
 * -----------------------------------------------
 * @Date: 2017年10月18日 下午2:30:31
 * @author: zsljava
 * @version 1.0.0
 * @OP: Create
 * -----------------------------------------------
 * </p>
 *
 * @since
 * @see
 */
@Service("verifyService")
public class VerifyServiceImpl implements IVerifyService{
	
	private Logger log = LoggerFactory.getLogger(VerifyServiceImpl.class);
	
	/**
	 * 移动图片的偏移量
	 */
	@Value("${verify.img.offset}")
	private int offset;
	
	/**
	 * 临界值  redis中验证图片少于criticalityValue，生成createValue张
	 */
	@Value("${verify.img.criticalityValue}")
	private int criticalityValue; 
	
	/**
	 * 临界值  redis中验证图片少于criticalityValue，生成createValue张
	 */
	@Value("${verify.img.createValue}")
	private int createValue; 
	
	@Autowired
	private StringRedisTemplate redisTemplate;
	
	@Autowired
	private IGenerateCodeService generateCodeService;
	
	@Autowired
	private IAuthService authService;
	
	/**
	 * threadPoolExecutorUtil
	 */
	private static ThreadPoolExecutorUtil threadPoolExecutorUtil = new ThreadPoolExecutorUtil();
	
	@Override
	public ImageVerify getVerifyCode() {
		// 获取集合大小
		Long size = redisTemplate.opsForSet().size(Const.VERIFY_CODE_SET);
		// 如果小于临界值则生成createValue 张验证码
		if(size <= criticalityValue){
			createValue = createValue < 10 ? 10 : createValue;
			log.debug("验证码少于{}张，执行生成命令，生成{}", criticalityValue, createValue);
			for (int i = 0; i < 10; i++) {
				threadPoolExecutorUtil.execute(()->{
					generateCodeService.generate(createValue / 10);
				});
			}
		}
		if(size == 0){
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// pop 移除并返回集合中的一个随机元素。
		String value = redisTemplate.opsForSet().pop(Const.VERIFY_CODE_SET);
		if(StringUtils.isNotEmpty(value)){
			ImageVerify img = JsonUtil.json2pojo(value, ImageVerify.class);
			img.setVerifyStartTime(new Date());
			String newKey = Const.REDIS_ALREADY_PREFIX.concat(img.getVerifyCode());
			redisTemplate.opsForValue().set(newKey, JsonUtil.obj2json(img), Const.DEFAULT_VERIFY_TIME_SECONDS, TimeUnit.SECONDS);
			
			img.setX(null);
			img.setOriginal(null);
			return img;
		}
		return new ImageVerify();
	}

	@Override
	public AuthVO verify(String appId, String newKey, int xvalue, int yvalue, String ip) {
		Auth auth = new Auth();
		auth.setIp(ip);
		auth.setAppId(appId);
		auth.setOffset(offset);
		auth.setAuthId(GeneratorKey.key());
		auth.setInputPointX(xvalue);
		auth.setInputPointY(yvalue);
		Date authStopTime = new Date();
		auth.setAuthStopTime(authStopTime);
		AuthVO av = new AuthVO();
		auth.setStatus(Const.VERIFY_STATUS_FAIL);
		// 避免int 溢出bug
		if(xvalue > 2000 || yvalue > 2000 || xvalue < 0 || yvalue < 0 ){ 
			auth.setReasonCode(VerifyEnum.VERIFY_AUTH_FAIL_ATTACK_INT.getCode());
			authService.addAuth(auth);
			BeanUtils.copyProperties(auth, av);
			return av;
		}
		
		boolean result = redisTemplate.hasKey(newKey);
		
		if(result){
			ImageVerify verify = JsonUtil.json2pojo(redisTemplate.opsForValue().get(newKey),ImageVerify.class);
			redisTemplate.delete(newKey);
			int offs = verify.getX() - xvalue;
			auth.setAuthStartTime(verify.getVerifyStartTime());
			auth.setVerifyCreateTime(verify.getCreateTime());
			Long authTime = authStopTime.getTime() - verify.getVerifyStartTime().getTime();
			auth.setAuthTime(authTime.intValue() / 1000);
			auth.setAuthX(verify.getX());
			auth.setAuthY(verify.getY());
			auth.setInputPointOffsetX(offs);
			auth.setInputPointOffsetY(offs);
			// 验证成功
			if(offs <= offset && offs >= -offset){ 
				auth.setStatus(Const.VERIFY_STATUS_SUCCESS);
				auth.setReasonCode(VerifyEnum.VERIFY_AUTH_SUCCESS.getCode());
				authService.addAuth(auth);
				BeanUtils.copyProperties(auth, av);
				return av;
			// 补图 移动位置不足
			}else{ 
				auth.setReasonCode(VerifyEnum.VERIFY_AUTH_FAIL_MOVE_IS_POSITION.getCode());
			}
		}else{
			auth.setReasonCode(VerifyEnum.VERIFY_AUTH_FAIL_CODE_NOT_EXIST.getCode());
		}
		
		authService.addAuth(auth);
		// 验证失败 验证码不存在
		BeanUtils.copyProperties(auth, av);
		return av;
		
	}
	
	
	
}
